package com.gistmap.sideline.web;

import com.gistmap.sideline.entity.Role;
import com.gistmap.sideline.entity.User;
import com.gistmap.sideline.exception.AppException;
import com.gistmap.sideline.exception.ResourceNotFoundException;
import com.gistmap.sideline.model.RoleName;
import com.gistmap.sideline.payload.*;
import com.gistmap.sideline.repository.RoleRepository;
import com.gistmap.sideline.repository.UserRepository;
import com.gistmap.sideline.security.JwtTokenProvider;
import com.gistmap.sideline.util.CodeCache;
import com.google.common.collect.Maps;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.util.Collections;
import java.util.Map;

import static com.gistmap.sideline.model.ErrorItems.USER_NOT_ACTIVE;

@RestController
@RequestMapping("/api/auth")
public class AuthController {

    @Autowired
    AuthenticationManager authenticationManager;

    @Autowired
    PasswordEncoder passwordEncoder;

    @Autowired
    UserRepository userRepository;

    @Autowired
    RoleRepository roleRepository;

    @Autowired
    JwtTokenProvider tokenProvider;

    @Autowired
    RabbitTemplate rabbitTemplate;


    @PostMapping("/activate")
    public Result isActivate(@Valid @RequestBody ActivateRequest request){
        Long userId = CodeCache.INSTANCE.get(request.getCode());
        if (userId != null) {
            // 提前移除验证通过的code
            CodeCache.INSTANCE.remove(request.getCode());
            // 更改状态为已激活
            userRepository.findById(userId).map( user -> {
                user.setActivate(true);
                User save = userRepository.save(user);
                return save;
            }).orElseThrow(() -> new ResourceNotFoundException("User", "id" , userId));
            return new Result().success("激活成功");
        } else {
            return new Result().fail("请求链接已超时效，请点击重新发送");
        }

    }
    @PostMapping("/signin")
    public Result authenticateUser(@Valid @RequestBody LoginRequest loginRequest) {

        userRepository.findByUsernameOrEmail(loginRequest.getUsernameOrEmail(),
                loginRequest.getUsernameOrEmail())
                .map( x -> x.isActivate() ? null :  new Result().error(USER_NOT_ACTIVE))
                .orElseThrow( () ->
                        new ResourceNotFoundException("User", "name or email", loginRequest.getUsernameOrEmail()));

        Authentication authentication = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(
                        loginRequest.getUsernameOrEmail(),
                        loginRequest.getPassword()
                )
        );

        SecurityContextHolder.getContext().setAuthentication(authentication);

        String jwt = tokenProvider.generateToken(authentication);
        return new Result().success(new JwtAuthenticationResponse(jwt));
    }

    @PostMapping("/signup")
    public Result registerUser(@Valid @RequestBody SignUpRequest signUpRequest) {
        if(userRepository.existsByUsername(signUpRequest.getUsername())) {
            return new Result().fail( "用户名已存在!");
        }

        if(userRepository.existsByEmail(signUpRequest.getEmail())) {
            return new Result().fail("邮箱已被注册!");
        }

        // Creating user's account
        User user = new User(signUpRequest.getName(), signUpRequest.getUsername(),
                signUpRequest.getEmail(), signUpRequest.getPassword());

        user.setPassword(passwordEncoder.encode(user.getPassword()));

        Role userRole = roleRepository.findByName(RoleName.ROLE_USER)
                .orElseThrow(() -> new AppException("角色未初始化."));

        user.setRoles(Collections.singleton(userRole));

        User saved = userRepository.save(user);

        Map<String, Object> map = Maps.newHashMap();
        map.put("id", saved.getId());
        map.put("username", saved.getUsername());
        map.put("email", saved.getEmail());

        // 发送邮件消息
        rabbitTemplate.convertAndSend("directExchange", "mailRouting", map);

        return new Result().success("注册成功");
    }
}
